package role

import (
	"context"
	"fmt"
	"github.com/zeromicro/go-zero/core/fx"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
	"go-admin/base/dao"
	"go-admin/base/utils"

	"go-admin/base/internal/svc"
	"go-admin/base/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type EditPermissionsLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewEditPermissionsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *EditPermissionsLogic {
	return &EditPermissionsLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *EditPermissionsLogic) EditPermissions(req *types.RolePermissionReqDTO) (resp *types.RoleBooleanRespDTOS, err error) {
	rolePermissions, err := l.svcCtx.RolePermissionModel.FindRolePermissionsByRoleIds(l.ctx, []int64{req.RoleID})

	permissionIdsDB := utils.Collector[int64](fx.From(func(source chan<- any) {
		for _, rolePermission := range rolePermissions {
			source <- rolePermission
		}
	}).Map(func(item any) any {
		rolePermission := item.(*dao.RolePermission)
		return rolePermission.PermissionId
	}))

	permissionIds := utils.Collector[int64](fx.From(func(source chan<- any) {
		for _, permission := range req.Permissions {
			source <- permission
		}
	}).Filter(func(item any) bool {
		permissionRespDTO := item.(types.PermissionRespDTO)
		return permissionRespDTO.RolePermissionID != 0
	}).Map(func(item any) any {
		permissionRespDTO := item.(types.PermissionRespDTO)
		return permissionRespDTO.PermissionID
	}))
	addPermissionIds := utils.Collector[int64](fx.From(func(source chan<- any) {
		for _, permission := range req.Permissions {
			source <- permission
		}
	}).Filter(func(item any) bool {
		permissionRespDTO := item.(types.PermissionRespDTO)
		return permissionRespDTO.RolePermissionID == 0
	}).Map(func(item any) any {
		permissionRespDTO := item.(types.PermissionRespDTO)
		return permissionRespDTO.PermissionID
	}))
	delPermissionIds := utils.Collector[int64](fx.From(func(source chan<- any) {
		for _, permissionId := range permissionIdsDB {
			source <- permissionId
		}
	}).Filter(func(item any) bool {
		permissionIdDB := item.(int64)
		return !utils.IsContain[int64](permissionIds, permissionIdDB)
	}))
	l.svcCtx.Conn.TransactCtx(l.ctx, func(ctx context.Context, session sqlx.Session) error {
		if len(delPermissionIds) > 0 {
			collector := utils.Collector[int64](fx.From(func(source chan<- any) {
				for _, rolePermission := range rolePermissions {
					source <- rolePermission
				}
			}).Filter(func(item any) bool {
				rolePermission := item.(*dao.RolePermission)
				if rolePermission.RoleId != req.RoleID {
					return false
				}
				return utils.IsContain[int64](delPermissionIds, rolePermission.PermissionId)
			}))
			err := l.svcCtx.RolePermissionModel.DeleteByIdsSession(l.ctx, session, collector)
			if err != nil {
				fmt.Errorf(err.Error())
				return err
			}
		}

		if len(addPermissionIds) > 0 {
			var rolePermissionAdd []*dao.RolePermission
			for _, permissionId := range addPermissionIds {
				rolePermission := &dao.RolePermission{
					PermissionId: permissionId,
					RoleId:       req.RoleID,
				}
				rolePermissionAdd = append(rolePermissionAdd, rolePermission)
			}
			err2 := l.svcCtx.RolePermissionModel.BatchInsert(l.ctx, sqlx.NewSqlConnFromSession(session), rolePermissionAdd)
			if err2 != nil {
				return err2
			}
		}
		return nil
	})
	return &types.RoleBooleanRespDTOS{
		Data: true,
		Result: types.Result{
			Code: 200,
		},
	}, nil
}
